#include <REG52.H> // 引入STC89C52头文件
#include <stdio.h>
#include <intrins.h>

// --- 硬件定义 ---

// 数码管位选引脚定义 (P2口)
// P2.4 = 位1 (最左)
// P2.5 = 位2
// P2.6 = 位3
// P2.3 = 位4 (最右)
sbit DIGIT1 = P2^5; // 位1
sbit DIGIT2 = P2^6; // 位2
sbit DIGIT3 = P2^7; // 位3
sbit DIGIT4 = P2^4; // 位4

sbit SPEAKER=P1^2;
sbit LED=P1^3;

sbit KEY_DOWN=P3^2; //减
sbit KEY_UP=P3^3; //加
sbit KEY_ENTER=P3^4; //设置
 
// DS18B20 定义
sbit DQ = P1^4;    // DS18B20数据线

// 数码管段码表 (共阳极, 0亮1灭)
// P0口连接顺序: P0.0=A, P0.1=E, P0.2=D, P0.3=DP, P0.4=F, P0.5=C, P0.6=G, P0.7=B
// P0位顺序: P0.7 P0.6 P0.5 P0.4 P0.3 P0.2 P0.1 P0.0
// 段码顺序: B    G    C    F    DP   D    E    A
unsigned char code Segment_Codes[] = {
    //   B G C F DP D E A
    0x48, // 0: 01001000
    0x5F, // 1: 01011111
    0x38, // 2: 00111000
    0x1A, // 3: 00011010
    0x0F, // 4: 00001111
    0x8A, // 5: 10001010
    0x88, // 6: 10001000
    0x5E, // 7: 01011110
    0x08, // 8: 00001000
    0x0A,  // 9: 00001010
    0x4C, // L: 01001100 (显示L)
    0x0E  // H: 00001110 (显示H)
};
#define LED_dot 0xF7 //小数点的断码位置

// --- 全局变量 ---
//按键处理
unsigned char key_down_flag=0;//减
unsigned char key_up_flag=0; //加
unsigned char key_enter_flag=0;//确定/设置
unsigned char key_press_flag=0;//有按键按下
unsigned char key_process_flag=0;//按键处理标识
// 显示缓冲区, 存储每位要显示的数字 {位1, 位2, 位3, 位4}
unsigned char display_buffer[4] = {1, 2, 3, 4};
// 当前正在扫描的数码管位 (0-3)
unsigned char current_digit = 0;

//按键扫描
unsigned char key_scan(void);

// DS18B20 函数声明
unsigned char DS18B20_Init(void);
void DS18B20_WriteByte(unsigned char dat);
unsigned char DS18B20_ReadByte(void);
void DS18B20_Start(void);
float DS18B20_GetTemp(void);

// 串口函数声明
void UART_Init(void);
void UART_SendString(char *s);
void UART_SendChar(unsigned char c);
void UART_SendFloat(float num);
// 延时函数声明
void delay(unsigned int t);
void delay_us(unsigned int us);
void delay_ms(unsigned int ms);
void Timer0_Init();             // 定时器0初始化
void Display_Refresh();         // 数码管动态刷新

// --- 函数声明 ---

void Display_Refresh(void)
{
   static unsigned char dis_bit=1;
   switch(dis_bit)
   {
        case 1:
            DIGIT1=1;DIGIT2=1;DIGIT3=1;DIGIT4=1;
            P0=Segment_Codes[display_buffer[0]];
            DIGIT1=0;DIGIT2=1;DIGIT3=1;DIGIT4=1;
            dis_bit++;
            break;
        case 2:DIGIT1=1;DIGIT2=1;DIGIT3=1;DIGIT4=1;
            P0=Segment_Codes[display_buffer[1]];
            DIGIT1=1;DIGIT2=0;DIGIT3=1;DIGIT4=1;
            dis_bit++;
            break;
        case 3:DIGIT1=1;DIGIT2=1;DIGIT3=1;DIGIT4=1;

            P0=Segment_Codes[display_buffer[2]] & LED_dot;
            DIGIT1=1;DIGIT2=1;DIGIT3=0;DIGIT4=1;
            dis_bit++;
            break;
        case 4:DIGIT1=1;DIGIT2=1;DIGIT3=1;DIGIT4=1;
            P0=Segment_Codes[display_buffer[3] ];
            DIGIT1=1;DIGIT2=1;DIGIT3=1;DIGIT4=0;
            dis_bit=1;
            break;  
        default:
            dis_bit=1;
            break;
   }    

}
void BootGif(void)
{
	unsigned char i;
    for ( i = 0; i < 2; i++)
    {
  		P0=Segment_Codes[i];
        DIGIT1=0;
        DIGIT2=0;
        DIGIT3=0;
        DIGIT4=0;
        delay_ms(500);
    } 
		//SPEAKER=0;
		LED=0;
		delay_ms(1000);
		//SPEAKER=1;
		LED=1;
}
//状态机法按键扫描
unsigned char  key_scan(void)
{
    static unsigned char key_up_old=1;
    static unsigned char key_down_old=1;
    static unsigned char key_enter_old=1;
    unsigned char key_up_new=KEY_UP;
    unsigned char key_down_new=KEY_DOWN;
    unsigned char key_enter_new=KEY_ENTER;
    if(key_up_old==1&&key_up_new==0)
    {
        key_up_flag=1;
    }
    key_up_old=key_up_new;
    if(key_down_old==1&&key_down_new==0)
    {
        key_down_flag=1;
            
    }
    key_down_old=key_down_new;
    if(key_enter_old==1 && key_enter_new==0)
    {
        key_enter_flag=1;
    }
    key_enter_old=key_enter_new;  
    
    if(key_up_flag==1 || key_down_flag==1 || key_enter_flag==1)
    {
        return 1;
    }
    else
    {
        return 0;   
    }
}

// --- DS18B20驱动函数 ---

// DS18B20初始化函数 - 优化时序
unsigned char DS18B20_Init(void) {
    // unsigned char presence = 1;
    
    // DQ = 1;            // 拉高数据线
    // delay_us(1);       // 短暂延时    
    // DQ = 0;            // 发送复位脉冲
    // delay_us(90);     // 延时80*12=960us (至少480us)    
    // DQ = 1;            // 释放总线
    // delay_us(8);      // 等待60us (15-60us之间读取存在脉冲)    
    // presence = DQ;     // 读取存在脉冲
    // delay_us(5);     // 完成存在脉冲时序 (总释放时间需大于480us)    
    // return presence;   // 返回0表示检测到DS18B20，1表示未检测到

    unsigned char x=0;
    DQ = 1;      //DQ??
    delay(8);    //????
    DQ = 0;      //????DQ??
    delay(80);   //????,??480us
    DQ = 1;      //????
    delay(8);
    x = DQ;      //?????,??x=0??????,x=1??????
    delay(4);
    return x;
}

// DS18B20写一个字节 - 优化时序
void DS18B20_WriteByte(unsigned char dat) {
  unsigned char i=0;
  for (i=8; i>0; i--)
  {
    DQ = 0;
    DQ = dat&0x01;
	delay(4);
    DQ = 1;
    dat>>=1;
  }
  delay(4);
}

// DS18B20读一个字节 - 优化时序
unsigned char DS18B20_ReadByte(void) {
    // unsigned char i, dat = 0;
    
    // for(i = 0; i < 8; i++) {
    //     DQ = 0;            // 拉低总线开始读时序
    //     delay_us(2);       // 延时2us
        
    //     DQ = 1;            // 释放总线
    //     delay_us(10);      // 等待10us (DS18B20数据有效时间)
        
    //     dat >>= 1;         // 准备接收数据
    //     if(DQ) dat |= 0x80; // 读取数据位
        
    //     delay_us(50);      // 完成读时隙 (总时隙时间至少60us)
    // }
    // return dat;
    unsigned char i=0;
    unsigned char dat = 0;
    for (i=8;i>0;i--)
    {
        DQ = 0;     // ?????
        dat>>=1;
        DQ = 1;     // ?????
        if(DQ)
            dat|=0x80;
        delay(4);
    }
    return(dat);
}

// DS18B20开始温度转换
void DS18B20_Start(void) {
    if(DS18B20_Init() == 0) {      // 初始化并检查DS18B20是否存在
        DS18B20_WriteByte(0xCC);   // 跳过ROM匹配
        DS18B20_WriteByte(0x44);   // 开始温度转换
    }
}

// DS18B20获取温度值 - 增加错误检查
float DS18B20_GetTemp(void) {
    unsigned char Temp_H = 0, Temp_L = 0;
    int raw = 0;
    float temp;

    if (DS18B20_Init()) return 0;
    //启动转换
    DS18B20_WriteByte(0xCC);  // Skip ROM
    DS18B20_WriteByte(0x44);  // Convert T
    delay_ms(750);        // Wait for conversion complete,about 750ms
    //初始化    
    if (DS18B20_Init()) return 0;
    //读取数据
    DS18B20_WriteByte(0xCC);  // Skip ROM
    DS18B20_WriteByte(0xBE);  // Read scratchpad

    Temp_L = DS18B20_ReadByte();   // LSB
    Temp_H = DS18B20_ReadByte();   // MSB

    raw = (Temp_H << 8) | Temp_L;

    if (raw < 0 || raw > 0x07D0) return 0;  // 0x07D0 = 2000
    //转换为温度值
    temp = (float)(raw * 0.0625);  // Convert to float Celsius
    return temp;
}

void get_display_buffer(unsigned int temp_int)
{
    display_buffer[3] = temp_int % 10;           // 小数部分
    display_buffer[2] = (temp_int % 100) / 10;    // 个位
    display_buffer[1] = (temp_int % 1000) / 100;   // 十位 
    display_buffer[0] = (temp_int % 10000) /1000;   // 十位 
}

// 更新显示缓冲区（将温度值转换为显示数据）
void update_display_buffer(float temp) {
   unsigned int temp_int;
    
    // 处理负温度
    // if(temp < 0) {
    //     display_buffer[0] = 0x40;  // 显示负号
    //     temp = -temp;
    // } else {
    //     display_buffer[0] = 0x00;  // 不显示符号
    // }
    
    // 将温度值扩大10倍，保留一位小数
    temp_int = (unsigned int)(temp*10);
    
    // 分解温度值为各个数位   

    get_display_buffer(temp_int);
}

// 按键设置处理函数
void handle_key_settings(unsigned int *Temp_L, unsigned int *Temp_H, unsigned char *setting_mode, unsigned char *key_process_flag) {
    if(key_scan()) {     
        if(key_enter_flag == 1) {
            key_enter_flag = 0;
            *setting_mode = (*setting_mode + 1) % 3;  // 循环切换模式
            
            if(*setting_mode == 0) {
                *key_process_flag = 0;  // 退出设置模式
            }
            else if(*setting_mode == 1) {
                *key_process_flag = 1;
            }
            else if(*setting_mode == 2) {
                *key_process_flag = 1;
                              
            }
        }
        
        if(*setting_mode > 0)  // 在设置模式下
        {
            if(key_up_flag == 1) {
                key_up_flag = 0;
                if(*setting_mode == 1) {    
                    *Temp_L += 10;  // 增加0.1°C
                }
                else {
                    *Temp_H += 10;  // 增加0.1°C
                }
            }
            if(key_down_flag == 1) {
                key_down_flag = 0;
                if(*setting_mode == 1) {
                    *Temp_L -= 10;  // 减少0.1°C
                }
                else {
                    *Temp_H -= 10;  // 减少0.1°C
                }
            }
            
            // 显示当前设置值
            if(*setting_mode == 1) {                   
                get_display_buffer(*Temp_L);
            }
            else {                 
                get_display_buffer(*Temp_H);
            }
        }
    }
}

    // --- 主函数 ---

void main() {
    float temperature = 12;
    unsigned int key_cnt_test = 0, i, setting_mode = 0;
    unsigned char temp_display[4];
    unsigned int key_temp_value = 0;
    unsigned int Temp_L = 200;  // 温度下限
    unsigned int Temp_H = 350;  // 温度上限
    UART_Init();
    Timer0_Init();    // 初始化定时器0  
    EA = 1;  // 开启总中断 
    BootGif();  
    UART_SendString("Hello, World!\n\r");
    // 初始化DS18B20
    if(DS18B20_Init() == 0) {
        LED = 0;  // 初始化成功，LED亮
        UART_SendString("Init  OK!\n\r");
    } else {
        LED = 1;  // 初始化失败，LED灭
        UART_SendString("Init  Error!\n\r");
    }    

    get_display_buffer(1234);  key_process_flag=0;
    while (1) {
        temperature = DS18B20_GetTemp();  // 读取温度值
        UART_SendFloat(temperature);     // 通过UART向电脑发送温度值
				if(temperature>1){//温度值有效
					if(temperature*10 < Temp_L)
					{
							UART_SendString("   Temp_L\n\r");
							SPEAKER=0;
							delay_ms(100);
							SPEAKER=1;
					}
					else if(temperature*10 > Temp_H)
					{
							UART_SendString("   Temp_H\n\r");
							SPEAKER=0;
							delay_ms(100);
							SPEAKER=1;
					}
					if(key_process_flag == 0) {  // 无按键时显示温度值
							update_display_buffer(temperature);  // 更新数码管显示缓冲区
        }
        
        // 调用按键设置处理函数
        handle_key_settings(&Temp_L, &Temp_H, &setting_mode, &key_process_flag);
			}
        LED = !LED;
        delay_ms(250);  // 延时250ms再次读取
    }
}

// 针对12MHz晶振优化的延时函数，一个循环大改12us
void delay(unsigned int t)
{
	for(;t>0;t--);
}
// 微秒延时函数
void delay_us(unsigned int us) {
    // 12MHz晶振下，1个机器周期为1us
   // while(us--) ;
	for(;us>0;us--);  
}

// 毫秒延时函数
void delay_ms(unsigned int ms) {
    unsigned int i, j;
    for(i = 0; i < ms; i++) {
        for(j = 0; j < 125; j++) {  // 12MHz下约1ms
            _nop_();
        }
    }
}
// --- 定时器0初始化 ---

void Timer0_Init() {
    TMOD |= 0x01; // 定时器0工作在模式1 (16位定时器)

    // 计算初值实现约5ms中断
    // Fosc = 11.0592 MHz, 机器周期 = 1.085 us
    // 5ms / 1.085 us/周期 = 4608 周期
    // 计数初值 = 65536 - 4608 = 60928 = 0xEDC0
    TH0 = 0xED; // 定时器高8位
    TL0 = 0xC0; // 定时器低8位

    ET0 = 1;    // 允许定时器0中断
    TR0 = 1;    // 启动定时器0
}

// 串口初始化函数
// 串口初始化（4800bps@12MHz，使用定时器1）
void UART_Init(void) {
    SCON = 0x50;    // 8位数据，可变波特率
    TMOD |= 0x20;   // 设置定时器1为模式2（自动重装载）
    
    PCON |= 0x80;   // SMOD=1，波特率加倍
    TH1 = 0xF3;     // 4800bps@12MHz (SMOD=1)
    TL1 = 0xF3;

    TR1 = 1;        // 启动定时器1
    // ES = 0;         // 使能串口中断
    
}
 

// 发送一个字符
void UART_SendChar(unsigned char c) {
    SBUF = c;
    while(TI == 0); // 等待发送完成
    TI = 0;         // 清除发送中断标志
}
// 串口发送函数
// 发送字符串
void UART_SendString(char *str) {
    while(*str) {
        UART_SendChar(*str++);
    }
}

// 发送浮点数
void UART_SendFloat(float num) {
    char buff[10];
    sprintf(buff,"%.2f",num);
    UART_SendString(buff);
}

// 串口中断服务函数
void UART_ISR(void) interrupt 4 {
    if(RI) {
        RI = 0;                 // 清除接收中断标志
 
    }
    if(TI) {
        TI = 0;                 // 清除发送中断标志
    }
}
// --- 定时器0中断服务程序 ---

void Timer0_ISR() interrupt 1 {
	   static unsigned char ii=0;
    // 重新装载定时器初值
    TH0 = 0xED;
    TL0 = 0xC0;
    Display_Refresh();
    key_scan();
}

